class IUP_CELLS
-- Creates a grid widget (set of cells) that enables several 
-- application-specific drawing, such as: chess tables, tiles editors, degrade 
-- scales, drawable spreadsheets and so forth.
--
-- This element is mostly based on application callbacks functions that 
-- determine the number of cells (rows and columns), their appearance and 
-- interaction. This mechanism offers full flexibility to applications, but 
-- requires programmers attention to avoid infinite loops inside this 
-- functions. Using callbacks, cells can be also grouped to form major or 
-- hierarchical elements, such as headers,  footers etc. This callback approach 
-- was intentionally chosen to allow all cells to be dynamically and directly 
-- changed based on application's data structures. Since the size of each cell 
-- is given by the application the size of the control also must be given using 
-- size or raster_size attributes.
--
-- It inherits from IUP_CANVAS. 

inherit
	IUP_CONTROLS
		rename
			canvas as cells
		redefine
			cells,
			get_cd_canvas,
			execute_draw,
			execute_height,
			execute_hspan,
			execute_mouseclick,
			execute_mousemotion,
			execute_ncols,
			execute_nlines,
			execute_scrolling,
			execute_vspan,
			execute_width
		end

create {ANY}
	cells

feature {ANY}

	cells
		local
			a_cells: POINTER
		do
			a_cells := int_cells
			set_widget(a_cells)
		end

	-- Attributes

	set_boxed (state: BOOLEAN)
		-- Determines if the bounding cells' regions should be drawn with black 
		-- lines. Default: "True". If the "span" attributes are used, set this 
		-- attribute to "False" to avoid grid drawing over spanned cells.
		do
			iup_open.set_attribute(Current, "BOXED", boolean_to_yesno(state))
		end

	set_bufferize (state: BOOLEAN)
		-- Disables the automatic redrawing of the control, so many attributes 
		-- can be changed without many redraws. When set to "False" the control 
		-- is redrawn. When REPAINT attribute is set, BUFFERIZE is automatically 
		-- set to "False". Default: "False". 
		do
			iup_open.set_attribute(Current, "BUFFERIZE", boolean_to_yesno(state))
		end

	get_cd_canvas: CD_IUP
		-- (non inheritable): Returns the internal IUP CD canvas. This 
		-- attribute should be used only in specific cases and by experienced 
		-- CD programmers.
		local
			p: POINTER
		do
			p := iup_open.get_attribute_ihandle(Current, "CANVAS")
			
			Result := internal_cd(p)
		end

	set_clipped (state: BOOLEAN)
		-- Determines if, before cells drawing, each bounding region should be 
		-- clipped. This attribute should be changed in few specific cases. 
		-- Default: "True".
		do
			iup_open.set_attribute(Current, "CLIPPED", boolean_to_yesno(state))
		end

	get_first_column: INTEGER
		--	Returns the number of the first visible column. 
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "FIRST_COL")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	get_first_line: INTEGER
		--	Returns the number of the first visible line. 
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "FIRST_LINE")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	set_full_visible (line, column: INTEGER)
		-- Tries to show completely a specific cell (considering any vertical or 
		-- horizontal header or scrollbar position).
		local
			value: STRING
		do
			create value.make_from_string(line.to_string)
         value.append_string(":")
         value.append_string(column.to_string)

			iup_open.set_attribute(Current, "FULL_VISIBLE", value)
		end

	-- Skip image_canvas

	get_limits (line, column: INTEGER): TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]
		-- Returns the limits of a given cell.
		local
			str: STRING
		do
			str := iup_open.get_attribute_id2 (Current, "LIMITS", line, column)
			Result := components_of_limits(str)
		end

	set_non_scrollable_lines (number: INTEGER)
		-- Determines the number of non-scrollable lines (vertical headers) that 
		-- should always be visible despite the vertical scrollbar position. It 
		-- can be any non-negative integer value. Default: "0".
		require
			number >= 0
		do
			iup_open.set_attribute(Current, "NON_SCROLLABLE_LINES",
										  number.to_string)
		end

	set_non_scrollable_columns (number: INTEGER)
		-- Determines the number of non-scrollable columns (horizontal headers) 
		-- that should always be visible despite the horizontal scrollbar 
		-- position. It can be any non-negative integer value. Default: "0".
		require
			number >= 0
		do
			iup_open.set_attribute(Current, "NON_SCROLLABLE_COLS",
										  number.to_string)
		end

	set_origin (line, column: INTEGER)
		-- Sets the first visible line and column positions.
		local
			value: STRING
		do
			create value.make_from_string(line.to_string)
         value.append_string(":")
         value.append_string(column.to_string)

			iup_open.set_attribute(Current, "ORIGIN", value)
		end

	set_scrollbar (state: BOOLEAN)
		-- Default: "True".
		do
			iup_open.set_attribute(Current, "SCROLLBAR", boolean_to_yesno(state))
		end
	
	-- Operations

	repaint
		-- Provokes the control to be redrawn.
		do
			iup_open.set_attribute(Current, "REPAINT", "Yes")
		end

	-- Callbacks

	set_cb_draw (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, CD_IUP], STRING])
		--  Called when a specific cell needs to be redrawn.
		--
		-- ih: identifier of the element that activated the event.
		-- line, column: the grid position inside the control that is being 
		--     redrawn, in grid coordinates.
		-- xmin, xmax, ymin, ymax: the raster bounding box of the redrawn cells, 
		--     where the application can use CD functions to draw anything. If 
		--     the attribute IUP_CLIPPED is set (the default), all CD graphical 
		--     primitives is clipped to the bounding region.
		-- canvas: internal canvas CD used to draw the cells.
		--
		-- Returns: "IUP_DEFAULT", "IUP_CONTINUE" or "IUP_IGNORE"
		local
			operation: INTEGER
		do
			cb_draw := act

			if cb_draw /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DRAW_CB", "NONEEDED", operation)
		end

	set_cb_height (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER], INTEGER])
		-- Called when the controls needs to know a (eventually new) line height.
		--
		-- ih: identifier of the element that activated the event.
		-- line: the line index
		-- 
		-- Returns: an integer that specifies the desired height (in pixels). 
		--          Default is 30 pixels.
		local
			operation: INTEGER
		do
			cb_height := act

			if cb_height /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "HEIGHT_CB", "NONEEDED", operation)
		end

	set_cb_horizontal_span (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], INTEGER])
		-- Called when the control needs to know if a cell should be horizontally 
		-- spanned.
		--
		-- ih: identifier of the element that activated the event.
		-- line, column: the line and column indexes (in grid coordinates)
		--
		-- Returns: an integer that specifies the desired span.
		--          Default is 1 (no span).	
		local
			operation: INTEGER
		do
			cb_hspan := act

			if cb_hspan /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "HSPAN_CB", "NONEEDED", operation)
		end

	set_cb_mouse_click (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING])
		-- Same as "set_cb_button" at IUP_CANVAS callback with two additional 
		-- parameters (the third and fourth integers):
		--
		-- IUP_CELLS: identifies the element that activated the event.
		-- button:    as in "set_cb_button"
		-- pressed:   as in "set_cb_button"
		-- line, column: the grid position in the control where the event has 
		--               occurred, in grid coordinates.
		-- x, y:      as in "set_cb_button"
		-- status:    as in "set_cb_button"
		local
			operation: INTEGER
		do
			cb_mouseclick := act

			if cb_mouseclick /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "MOUSECLICK_CB", "NONEEDED", operation)
		end

	set_cb_mouse_motion (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING])
		-- Called when the mouse moves over the control.
		--
		-- Same as the "set_cb_motion" IUP_CANVAS callback with two additional 
		-- parameters:
		--
		-- line, column: the grid position in the control where the event has 
		--               occurred, in grid coordinates.
		local
			operation: INTEGER
		do
			cb_mousemotion := act

			if cb_mousemotion /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "MOUSEMOTION_CB", "NONEEDED", operation)
		end

	set_cb_number_of_columns (act: FUNCTION[TUPLE[IUP_CELLS], INTEGER])
		-- Called when then controls needs to know its number of columns.
		--
		-- ih: identifier of the element that activated the event.
		--
		-- Returns: an integer that specifies the number of columns.
		--          Default is 10 columns.
		local
			operation: INTEGER
		do
			cb_ncols := act

			if cb_ncols /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "NCOLS_CB", "NONEEDED", operation)
		end

	set_cb_number_of_lines (act: FUNCTION[TUPLE[IUP_CELLS], INTEGER])
		-- Called when then controls needs to know its number of lines.
		--
		-- ih: identifier of the element that activated the event.
		--
		-- Returns: an integer that specifies the number of lines.
		--          Default is 10 lines.
		local
			operation: INTEGER
		do
			cb_nlines := act

			if cb_nlines /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "NLINES_CB", "NONEEDED", operation)
		end

	set_cb_scrolling (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], STRING])
		-- Called when the scrollbars are activated.
		--
		-- ih: identifier of the element that activated the event.
		-- line, column: the first visible line and column indexes (in grid 
		--               coordinates)
		--
		-- Returns: If "IUP_IGNORE" the cell is not redrawn. By default the cell
		-- is always redrawn.
		local
			operation: INTEGER
		do
			cb_scrolling := act

			if cb_scrolling /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "SCROLLING_CB", "NONEEDED", operation)
		end

	set_cb_vertical_span (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], INTEGER])
		-- Called when the control needs to know if a cell should be vertically 
		-- spanned.
		--
		-- ih: identifier of the element that activated the event.
		-- line, column: the line and column indexes (in grid coordinates)
		--
		-- Returns: an integer that specifies the desired span.
		--          Default is 1 (no span).
		local
			operation: INTEGER
		do
			cb_vspan := act

			if cb_vspan /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "VSPAN_CB", "NONEEDED", operation)
		end

	set_cb_width (act: FUNCTION[TUPLE[IUP_CELLS, INTEGER], INTEGER])
		-- Called when the controls needs to know the column width.
		--
		-- ih: identifier of the element that activated the event.
		-- column: the column index
		--
		-- Returns: an integer that specifies the desired width (in pixels).
		-- Default is 60 pixels.
		local
			operation: INTEGER
		do
			cb_width := act

			if cb_width /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "WIDTH_CB", "NONEEDED", operation)
		end


feature {IUP}

	execute_draw (line, column, xmin, xmax, ymin, ymax: INTEGER; canvas: POINTER): STRING
		do
			Result := cb_draw.item([Current, line, column, xmin, xmax, ymin, ymax, internal_cd(canvas)])
		end

	execute_height (line: INTEGER): INTEGER
		do
			Result := cb_height.item([Current, line])
		end

	execute_hspan (line, column: INTEGER): INTEGER
		do
			Result := cb_hspan.item([Current, line, column])
		end

	execute_mouseclick (btn, prd, l, c, x, y: INTEGER; s: STRING): STRING
		do
			Result := cb_mouseclick.item([Current, btn, prd, l, c, x, y, s])
		end

	execute_mousemotion (l, c, x, y: INTEGER; r: STRING): STRING
		do
			Result := cb_mousemotion.item([Current, l, c, x, y, r])
		end

	execute_ncols: INTEGER
		do
			Result := cb_ncols.item([Current])
		end

	execute_nlines: INTEGER
		do
			Result := cb_nlines.item([Current])
		end

	execute_scrolling (l, c: INTEGER): STRING
		do
			Result := cb_scrolling.item([Current, l, c])
		end

	execute_vspan (l, c: INTEGER): INTEGER
		do
			Result := cb_vspan.item([Current, l, c])
		end

	execute_width (c: INTEGER): INTEGER
		do
			Result := cb_width.item([Current, c])
		end

feature {}

	cb_draw: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, CD_IUP], STRING]

	cb_height: FUNCTION[TUPLE[IUP_CELLS, INTEGER], INTEGER]

	cb_hspan: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], INTEGER]

	cb_mouseclick: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING]

	cb_mousemotion: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING]

	cb_ncols: FUNCTION[TUPLE[IUP_CELLS], INTEGER]

	cb_nlines: FUNCTION[TUPLE[IUP_CELLS], INTEGER]

	cb_scrolling: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], STRING]

	cb_vspan: FUNCTION[TUPLE[IUP_CELLS, INTEGER, INTEGER], INTEGER]

	cb_width: FUNCTION[TUPLE[IUP_CELLS, INTEGER], INTEGER]


	-- Internals

	int_cells: POINTER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupCells()"
         }"
      end

end

-- The MIT License (MIT)

-- Copyright (c) 2016 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
